package com.kayb.patterns.behavioral;

/**
 * 职责链，有多个对象，每个对象持有下一个对象的引用，这样就形成一条链，请求在这条链上传递，指导某一对象觉得处理该请求
 * 场景：Dubbo的filter，Spring的Interceptor
 * @author huangkaibin
 * @date 2018-08-28
 **/
public class InterceptingFilter {

    interface Filter {
        void doFilter(String str);
        void next(Filter filter);
        Filter getNext();
        Filter getLast();
    }

    static abstract class AbstractFilter implements Filter {
        private Filter next;

        @Override
        public void next(Filter filter) {
            this.next = filter;
        }

        @Override
        public Filter getNext() {
            return next;
        }

        @Override
        public Filter getLast() {
            Filter last = this;
            while (last.getNext() != null) {
                last = last.getNext();
            }
            return last;
        }

        @Override
        public void doFilter(String str) {
            if (getNext() != null) {
                getNext().doFilter(str);
            }
        }
    }

    static class AFilter extends AbstractFilter {
        @Override
        public void doFilter(String str) {
            super.doFilter(str);
            System.out.println("AFilter before");
        }
    }

    static class BFilter extends AbstractFilter {
        @Override
        public void doFilter(String str) {
            super.doFilter(str);
            System.out.println("BFilter before");
        }
    }

    static class CFilter extends AbstractFilter {
        @Override
        public void doFilter(String str) {
            super.doFilter(str);
            System.out.println("CFilter before");
        }
    }

    static class FilterChain {
        private Filter chain;

        public void addFilter(Filter filter) {
            if (chain == null) {
                chain = filter;
            } else {
                chain.getLast().next(filter);
            }
        }

        /**
         * Execute filter chain
         */
        public void execute(String string) {
            if (chain != null) {
                chain.doFilter(string);
            } else {
                System.out.println("RUNNING...");
            }
        }
    }

    static class FilterManager {
        private FilterChain filterChain;

        public FilterManager() {
            filterChain = new FilterChain();
        }

        public void addFilter(Filter filter) {
            this.filterChain.addFilter(filter);
        }

        public void doFilter(String str) {
            filterChain.execute(str);
        }
    }

    public static void main(String[] args) {
        FilterManager filterManager = new FilterManager();
        filterManager.addFilter(new AFilter());
        filterManager.addFilter(new BFilter());
        filterManager.addFilter(new CFilter());

        filterManager.doFilter("test");
    }

}
